//
// Created by zxh on 2019-12-19.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>

#include "usb_hotplug_check.h"
#include "uart_driver.h"
#include "common.h"

int hotplug_sock = 0;

#if DEBUG_BOARD_ARCH_TYPE == 0x00
uint8_t UsbSerialDevicePathIndex[USB_SERIAL_AMOUNT][64] =	\
                                            { \
                                               RK3399_USB_SERIAL_2_0_1_FILE_PATH,RK3399_USB_SERIAL_2_0_2_FILE_PATH, \
                                                NULL,NULL, \
                                                NULL,NULL,NULL,NULL \
                                            };
#else
uint8_t UsbSerialDevicePathIndex[USB_SERIAL_AMOUNT][64] =	\
                                            {HI3798_USB_SERIAL_3_0_FILE_PATH,HI3798_USB_SERIAL_2_0_FILE_PATH, \
                                                NULL,NULL, \
                                                NULL,NULL,NULL,NULL \
                                            };
#endif

STRUCT_USB_SERIAL_HOTPLUG_DETECTION UsbSerialHotplugDetectionStru = {0x00};

int init_hotplug_struct(uint8_t channelid,uint32_t bautrate)
{

    uint8_t i = 0x00;
    uint8_t cnt = 0x00;

    if ((channelid >= 0x00) &&(channelid < USB_SERIAL_AMOUNT))
    {

        UsbSerialHotplugDetectionStru.usbserialfd[channelid] = -1;

        UsbSerialHotplugDetectionStru.usbserialbautrate[channelid] = bautrate;
        UsbSerialHotplugDetectionStru.usbserialchannelenableflag[channelid] = 0x01;

        /*
         * 初始化串口索引 ：防止檢測到未使用的串口時，檢測到插拔信息之後，通過查詢得到的是在使用的串口設備，
         *                 造成串口索引返回異常，使正在使用的串口無法使用
         * */
        for (i = 0x00;i < USB_SERIAL_AMOUNT;i ++)
        {
            UsbSerialHotplugDetectionStru.usbseriachannellindex[i] = i;
        }

        /*对应通道的设备配置信息不存在*/
        if (UsbSerialDevicePathIndex[channelid] == NULL)
        {
            return -1;
        }
        memcpy(UsbSerialHotplugDetectionStru.usbserialdevicepath[channelid] ,UsbSerialDevicePathIndex[channelid],strlen(UsbSerialDevicePathIndex[channelid]));
    } else
    {
        for (i = 0x00;i < USB_SERIAL_AMOUNT;i ++)
        {
            UsbSerialHotplugDetectionStru.usbserialfd[i] = -1;

            UsbSerialHotplugDetectionStru.usbserialbautrate[i] = bautrate;
            UsbSerialHotplugDetectionStru.usbserialchannelenableflag[i] = 0x01;

            UsbSerialHotplugDetectionStru.usbseriachannellindex[i] = i;

            /*对应通道的设备配置信息不存在*/
            if (UsbSerialDevicePathIndex[i] != NULL)
            {
                cnt ++;
                memcpy(UsbSerialHotplugDetectionStru.usbserialdevicepath[i] ,UsbSerialDevicePathIndex[i],strlen(UsbSerialDevicePathIndex[i]));
            }
        }
        if (cnt == 0x00)
        {
            return -1;
        }
    }
	return 0x00;
}

int init_hotplug_sock(void)
{
    const int buffersize = 1024;
    int ret;

    struct sockaddr_nl snl;
    bzero(&snl, sizeof(struct sockaddr_nl));

    snl.nl_family = AF_NETLINK;
    snl.nl_pid = getpid();
    snl.nl_groups = 1;

    int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (s == -1)
    {
        perror("socket");
        return -1;
    }
    setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));

    ret = bind(s, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));
    if (ret < 0)
    {
        perror("bind");
        close(s);
        return -1;
    }

    return s;
}

void * usb_device_hotplug_check_handle(void * arg)
{

    uint8_t i = 0x00;
    int ret = 0x00;
    int rcvlen = 0x00;

    int index = 0x00;

    /*usb 串口有拔出到插入 状态变化，usb串口状态更新时间间隔*/
    int usbserialinsertflag = 0x00;
    char buf[UEVENT_BUFFER_SIZE] = { 0 };

    struct timeval tv;
    fd_set fds;

    while (1)
    {

        FD_ZERO(&fds);
        FD_SET(hotplug_sock, &fds);

        tv.tv_sec = 30;
        tv.tv_usec = 0;

        ret = select(hotplug_sock + 1, &fds, NULL, NULL, &tv);
        if((!(ret > 0 && FD_ISSET(hotplug_sock, &fds)))||(ret < 0))
        {
            /*usb 串口发生 插入事件:延时30s 确保应用层能够检测到 usb串口插入事件*/
            for (i = 0x00;i < USB_SERIAL_AMOUNT;i ++)
            {
                if (((UsbSerialHotplugDetectionStru.usbserialinsertflag >> (i << 1)) & 0x00000003)== 0x01)
                {

                    LOGD("usb serial states update:usb serial %d insert",i);

                    UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (i << 1));
                    UsbSerialHotplugDetectionStru.usbserialhotplugstats |= (0x01 << (i << 1));

                    UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 <<(i << 1));
                }
            }
            continue;
        }

        /* receive data */
        rcvlen = recv(hotplug_sock, buf, sizeof(buf), 0);
        if (rcvlen > 0)
        {

            LOGD ("%s\n",buf);

		   #if DEBUG_BOARD_ARCH_TYPE == 0x00
           /*usb serial 拔出*/
           if((strstr(buf,RK3399_USB_SERIAL_2_0_1_DELETE_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(RK3399_USB_SERIAL_2_0_1_DELETE_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   LOGD("usb %d serial remove",index);

                   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
                   UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (index << 1));
               }
           }
		    else if( (strstr(buf,RK3399_USB_SERIAL_2_0_2_DELETE_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(RK3399_USB_SERIAL_2_0_2_DELETE_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   LOGD("usb %d serial remove",index);

                   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
                   UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (index << 1));
               }
           }
           /*usb serial 插入*/
           else if ((strstr(buf,RK3399_USB_SERIAL_2_0_1_INSERT_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(RK3399_USB_SERIAL_2_0_1_INSERT_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   /*当前usb串口状态 */
				   LOGD("usb %d serial insert",index);
				   
				   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
				   UsbSerialHotplugDetectionStru.usbserialinsertflag |= (0x01 << (index << 1));

               }
           }
		   /*usb serial 插入*/
           else if ((strstr(buf,RK3399_USB_SERIAL_2_0_2_INSERT_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(RK3399_USB_SERIAL_2_0_2_INSERT_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   /*当前usb串口状态 */
				   LOGD("usb %d serial insert",index);
				   
				   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
				   UsbSerialHotplugDetectionStru.usbserialinsertflag |= (0x01 << (index << 1));

               }
           }
		   #else
		   /*usb serial 拔出*/
           if((strstr(buf,HI3798_USB_SERIAL_3_0_DELETE_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(HI3798_USB_SERIAL_3_0_DELETE_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   LOGD("usb %d serial remove",index);

                   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
                   UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (index << 1));
               } else{
                   LOGD("not find index");
               }
           }
		    else if((strstr(buf,HI3798_USB_SERIAL_2_0_DELETE_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(HI3798_USB_SERIAL_2_0_DELETE_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   LOGD("usb %d serial remove",index);

                   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
                   UsbSerialHotplugDetectionStru.usbserialhotplugstats &= ~(0x03 << (index << 1));
               }
               else{
                   LOGD("not find index");
               }
           }
           /*usb serial 插入*/
           else if ((strstr(buf,HI3798_USB_SERIAL_3_0_INSERT_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(HI3798_USB_SERIAL_3_0_INSERT_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   /*当前usb串口状态 */
				   LOGD("usb %d serial insert",index);
				   
				   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
				   UsbSerialHotplugDetectionStru.usbserialinsertflag |= (0x01 << (index << 1));

               }
               else{
                   LOGD("not find index");
               }
           }
		   /*usb serial 插入*/
           else if ((strstr(buf,HI3798_USB_SERIAL_2_0_INSERT_PROMPT) != NULL))
           {
               /*根据提示 查找对应的串口序号*/
               index = check_usb_serial_device_index(HI3798_USB_SERIAL_2_0_INSERT_PROMPT);
               if ((index >= 0x00) && (index < USB_SERIAL_AMOUNT))
               {
                   /*当前usb串口状态 */
				   LOGD("usb %d serial insert",index);
				   
				   UsbSerialHotplugDetectionStru.usbserialinsertflag &= ~(0x03 << (index << 1));
				   UsbSerialHotplugDetectionStru.usbserialinsertflag |= (0x01 << (index << 1));
               }
               else{
                   LOGD("not find index");
               }
           }
           else
           {
               LOGD("not find prompt,exit");
           }
		   #endif
		   
           memset (buf ,0,strlen(buf));
        }
    }

    close(hotplug_sock);
    return 0;

}



/*****************************************************************************************
 * 获取当前usb串口设备状态
 *
 *定义说明		标记从低向高 每 2个位代表一个通道的usb串口状态  
 *返回值 		0 ：usb串口未连接 
 *			1:usb 串口已连接 
 *			2： 串口连接成功但初始化失败 
 *			3 ：usb串口连接并进行初始化成功
 *
 *
 * *****************************************************************************************/
int get_usb_serial_device_status(uint8_t channel)
{
    if (channel == 0xff)
    {
        return UsbSerialHotplugDetectionStru.usbserialhotplugstats;
    }
	else if ((channel >= 0x00) ||(channel < USB_SERIAL_AMOUNT))
	{
        return ((UsbSerialHotplugDetectionStru.usbserialhotplugstats >> (channel << 1)) & 0x00000003);
	}
    return 0x00;
}


/**
*usb 串口号查号 ：根据路径查找对应的usb端口
*
*path :设备路径 
*
*返回值 ：<0 :检索失败  >=0:检索成功
**/
int check_usb_serial_device_index(uint8_t * path)
{
    uint8_t i = 0x00;
    for (i = 0x00;i < USB_SERIAL_AMOUNT;i ++)
    {
        if (strstr(path,UsbSerialHotplugDetectionStru.usbserialdevicepath[i]) != NULL)
        {
            break;
        }
    }
    if (i == USB_SERIAL_AMOUNT)
    {
       return -1;
    }
	return UsbSerialHotplugDetectionStru.usbseriachannellindex[i];
}

/**
*查找可用的usb串口设备通道
*
*参数：无
*
*返回值 ：成功 ：对应的通道值 0-7
 *           失败 ：-1
**/
int check_usable_usb_serial_channel(void)
{
    uint8_t i = 0x00;

    do
    {
        if (get_usb_serial_device_status(i) == USB_SERIAL_INIT_OK)
        {
            break;
        }
        i ++;
    }while(i < USB_SERIAL_AMOUNT);

    /*找到可用的通道*/
    if (i < USB_SERIAL_AMOUNT)
    {
        return i;
    }
    return -1;
}


